package com.sardine.base.utils;

import com.sardine.base.exception.SardineException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

/**
 * 上海京东到家元信信息技术有限公司<br>
 * Created with IntelliJ IDEA.
 * Date:2017/5/20
 * Time:12:02
 * 鲜豆系统检测参数异常问题
 * @author daifeng<br>
 *         daifeng@imdada.cn
 * @since JDK 1.7 <br>
 * Copyright (c) 2017 imdada System Incorporated All Rights Reserved.
 */
public abstract class ValidateArgUtils {
    private static final Logger logger = LoggerFactory.getLogger(ValidateArgUtils.class);
    private static final String NULL_STR = "null";
    public ValidateArgUtils() {
    }

    public static void isTrue(boolean expression, String message) {
        if(!expression) {
            throw new SardineException(message);
        }
    }

    public static void isTrue(boolean expression) {
        isTrue(expression, "[Assertion failed] - this expression must be true");
    }

    public static void isNull(Object object, String message) {
        if(object != null) {
            throw new SardineException(message);
        }
    }

    public static void isNull(Object object) {
        isNull(object, "[Assertion failed] - the object argument must be null");
    }

    public static void notNull(Object object, String message) {
        if(object == null) {
            throw new SardineException(message);
        }
    }

    public static void notNull(Object object) {
        notNull(object, "[Assertion failed] - this argument is required; it must not be null");
    }

    public static void hasLength(String text, String message) {
        if(!StringUtils.hasLength(text)) {
            throw new SardineException(message);
        }
    }

    public static void hasLength(String text) {
        hasLength(text, "[Assertion failed] - this String argument must have length; it must not be null or empty");
    }

    public static void hasText(String text, String message) {
        if(!StringUtils.hasText(text)) {
            throw new SardineException(message);
        }
    }

    public static void hasText(String text) {
        hasText(text, "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank");
    }

    public static void doesNotContain(String textToSearch, String substring, String message) {
        if(StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) && textToSearch.contains(substring)) {
            throw new SardineException(message);
        }
    }

    public static void doesNotContain(String textToSearch, String substring) {
        doesNotContain(textToSearch, substring, "[Assertion failed] - this String argument must not contain the substring [" + substring + "]");
    }

    public static void notEmpty(Object[] array, String message) {
        if(ObjectUtils.isEmpty(array)) {
            throw new SardineException(message);
        }
    }

    public static void notEmpty(Object[] array) {
        notEmpty(array, "[Assertion failed] - this array must not be empty: it must contain at least 1 element");
    }

    public static void noNullElements(Object[] array, String message) {
        if(array != null) {
            Object[] var2 = array;
            int var3 = array.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                Object element = var2[var4];
                if(element == null) {
                    throw new SardineException(message);
                }
            }
        }

    }

    public static void noNullElements(Object[] array) {
        noNullElements(array, "[Assertion failed] - this array must not contain any null elements");
    }

    public static void notEmpty(Collection<?> collection, String message) {
        if(CollectionUtils.isEmpty(collection)) {
            throw new SardineException(message);
        }
    }

    public static void notEmpty(Collection<?> collection) {
        notEmpty(collection, "[Assertion failed] - this collection must not be empty: it must contain at least 1 element");
    }

    public static void notEmpty(Map<?, ?> map, String message) {
        if(CollectionUtils.isEmpty(map)) {
            throw new SardineException(message);
        }
    }

    public static void notEmpty(Map<?, ?> map) {
        notEmpty(map, "[Assertion failed] - this map must not be empty; it must contain at least one entry");
    }

    public static void isInstanceOf(Class<?> clazz, Object obj) {
        isInstanceOf(clazz, obj, "");
    }

    public static void isInstanceOf(Class<?> type, Object obj, String message) {
        notNull(type, "Type to check against must not be null");
        if(!type.isInstance(obj)) {
            throw new SardineException((StringUtils.hasLength(message)?message + " ":"") + "Object of class [" + (obj != null?obj.getClass().getName():"null") + "] must be an instance of " + type);
        }
    }

    public static void isAssignable(Class<?> superType, Class<?> subType) {
        isAssignable(superType, subType, "");
    }

    public static void isAssignable(Class<?> superType, Class<?> subType, String message) {
        notNull(superType, "Type to check against must not be null");
        if(subType == null || !superType.isAssignableFrom(subType)) {
            throw new SardineException(message + subType + " is not assignable to " + superType);
        }
    }

    public static void state(boolean expression, String message) {
        if(!expression) {
            throw new SardineException(message);
        }
    }

    public static void state(boolean expression) {
        state(expression, "[Assertion failed] - this state invariant must be true");
    }

    /**
     * 检测非空字段，检查目标对象中的字段值是否都非空，若存在一个为空则未通过检测
     * @param target 被检查的目标对象
     * @param nonEmptyFields 非空的字段
     * @return true-通过检测，false-未通过检测
     */
    public static void checkFieldsNonEmpty(Object target, String[] nonEmptyFields,String message) {
        if (target == null) {
            throw new SardineException(message + "checkFieldsNonEmpty error : target is null ");
        }
        if (nonEmptyFields == null || nonEmptyFields.length == 0) {
            return;
        }
        Object fieldValue = null;
        for (String nonEmptyField : nonEmptyFields) {
            try {
                fieldValue = getFieldValue(target,target.getClass(), nonEmptyField);
            } catch (Exception e) {
                logger.error(String.format(message + "failure to get field value, fieldName is [%s], target is [%s]", nonEmptyField, target), e);
                throw new SardineException(String.format(message + "failure to get field value, fieldName is [%s], target is [%s]", nonEmptyField, target));
            }
            if (fieldValue == null
                    || fieldValue.toString().trim().length() == 0
                    || NULL_STR.equals(fieldValue)) {
                throw new SardineException(String.format(message + " fieldName is [%s], target is [%s] ,field value is null", nonEmptyField, target));
            }
        }
        return;
    }

    /**
     * 获取指定属性的值
     * @param target
     * @param clazz
     * @param fname
     * @return
     */
    public static Object getFieldValue(Object target, Class<?> clazz, String fname) {
        if (target == null || fname == null || "".equals(fname)) {
            return null;
        }
        boolean exCatched = false;
        try {
            String methodname = "get" + capitalize(fname);
            Field field = clazz.getDeclaredField(fname);
            if(field.getClass().equals(boolean.class)){
                methodname = "is" + capitalize(fname);
            }
            Method method = clazz.getDeclaredMethod(methodname);
            method.setAccessible(true);
            return method.invoke(target);
        } catch (NoSuchMethodException e) {
            exCatched = true;
        } catch (InvocationTargetException e) {
            exCatched = true;
        } catch (IllegalAccessException e) {
            exCatched = true;
        } catch (SecurityException e) {
            exCatched = true;
        } catch (NoSuchFieldException e) {
            exCatched = true;
        }

        if (exCatched) {
            try {
                Field field = clazz.getDeclaredField(fname);
                field.setAccessible(true);
                return field.get(target);
            } catch (Exception fe) {
                if (logger.isDebugEnabled()) {
                    logger.debug(fe.getMessage());
                }
            }
        }
        return null;
    }

    private static String capitalize(String str) {
        if (str == null || str.length() == 0) {
            return null;
        }
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
}
